

import java.io.File;

import java.io.IOException;

import javax.sound.sampled.AudioFormat;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.SourceDataLine;


import javazoom.spi.mpeg.sampled.file.*;


public class G4Player {
	
	private static int	DEFAULT_EXTERNAL_BUFFER_SIZE = 128000;
	
	public static void main(String args[])		
		throws Exception
	{
		AudioInputStream audioInputStream = null;
		
		String filename = null;
		File file = null;
		int	nSampleSizeInBits = 16;
		boolean	bBigEndian = false;
		String	strMixerName = null;
		
		
		

		int	nInternalBufferSize = AudioSystem.NOT_SPECIFIED;
		int	nExternalBufferSize = DEFAULT_EXTERNAL_BUFFER_SIZE;


		try{
			
			filename = args[0];
			file = new File(filename);

			
		}catch (Exception exception) {			
			
			System.out.println(exception.toString());
			System.out.println(exception.getCause());			
			
		}
		
		System.out.println(filename+"\n");
		MpegAudioFileReader mFileReader = new MpegAudioFileReader();
		audioInputStream = mFileReader.getAudioInputStream(file);
		
		AudioFormat audioFormat = audioInputStream.getFormat();
		
		
		DataLine.Info	info = new DataLine.Info(SourceDataLine.class, audioFormat, AudioSystem.NOT_SPECIFIED);
		boolean	bIsSupportedDirectly = AudioSystem.isLineSupported(info);
		
		if (!bIsSupportedDirectly){
			
			AudioFormat	sourceFormat = audioFormat;
			
			AudioFormat	targetFormat = new AudioFormat(
											AudioFormat.Encoding.PCM_SIGNED, sourceFormat.getSampleRate(),
											nSampleSizeInBits, sourceFormat.getChannels(),
											sourceFormat.getChannels() * (nSampleSizeInBits / 8),
											sourceFormat.getSampleRate(), bBigEndian
										);
			
			
			audioInputStream = AudioSystem.getAudioInputStream(targetFormat, audioInputStream);
			audioFormat = audioInputStream.getFormat();
		}	
		
		SourceDataLine	line = getSourceDataLine(strMixerName, audioFormat, nInternalBufferSize);
		
		if (line == null) {
			
			System.out.println("AudioPlayer: cannot get SourceDataLine for format " + audioFormat);
			System.exit(1);
			
		}
		
		line.start();
		
		
		int	nBytesRead = 0;
		byte[]	abData = new byte[nExternalBufferSize];
		
		while (nBytesRead != -1)
		{
			try
			{
				nBytesRead = audioInputStream.read(abData, 0, abData.length);
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
			
			if (nBytesRead >= 0)
			{
				int	nBytesWritten = line.write(abData, 0, nBytesRead);
			}
		}	
		
	}
	
	
	private static SourceDataLine getSourceDataLine(String strMixerName, AudioFormat audioFormat, int nBufferSize){
		/*
		*	Asking for a line is a rather tricky thing.
		*	We have to construct an Info object that specifies
		*	the desired properties for the line.
		*	First, we have to say which kind of line we want. The
		*	possibilities are: SourceDataLine (for playback), Clip
		*	(for repeated playback)	and TargetDataLine (for
		*	 recording).
		*	Here, we want to do normal playback, so we ask for
		*	a SourceDataLine.
		*	Then, we have to pass an AudioFormat object, so that
		*	the Line knows which format the data passed to it
		*	will have.
		*	Furthermore, we can give Java Sound a hint about how
		*	big the internal buffer for the line should be. This
		*	isn't used here, signaling that we
		*	don't care about the exact size. Java Sound will use
		*	some default value for the buffer size.
		*/
		
		SourceDataLine	line = null;
		DataLine.Info	info = new DataLine.Info(SourceDataLine.class, audioFormat, nBufferSize);
		
		try {
			
			if (strMixerName != null){
				
				Mixer.Info	mixerInfo = AudioCommon.getMixerInfo(strMixerName);
				
				if (mixerInfo == null) {
					
					System.out.println("AudioPlayer: mixer not found: " + strMixerName);
					System.exit(1);
					
				}
				
				Mixer	mixer = AudioSystem.getMixer(mixerInfo);
				line = (SourceDataLine) mixer.getLine(info);
				
			} else{
				
				line = (SourceDataLine) AudioSystem.getLine(info);
				
			}
			
			/*
			*	The line is there, but it is not yet ready to
			*	receive audio data. We have to open the line.
			*/
			line.open(audioFormat, nBufferSize);
		
		} catch (LineUnavailableException e) {
			System.out.println(e.toString()+"\n");
		
		} catch (Exception e) {
			System.out.println(e.toString()+"\n");
		}
		
		return line;
	}	

}
